#include "dahengcameradevice.h"
#include <QFile>
#include <QDateTime>
#include "../mainwindow.h"

//图像回调处理函数
static void GX_STDC OnFrameCallbackFun(GX_FRAME_CALLBACK_PARAM* pFrame)
{
    CameraViewWidget* pCameraViewWidget =  (CameraViewWidget*)pFrame->pUserParam;
    if (pFrame->status == GX_FRAME_STATUS_SUCCESS)
    {
        //对图像进行某些操作
        pCameraViewWidget->m_viewBox->SetImage(pFrame);

        //qDebug() << "One Frame";
    }

    return;
}

DahengCameraDevice::DahengCameraDevice(QObject *parent)
    : Device{parent}
{
    m_strIP = QString("192.168.3.203");

    connect(this,&DahengCameraDevice::finishSnapImage,MainWindow::instance(),&MainWindow::on_finishSanpImage_signal);
}

DahengCameraDevice::DahengCameraDevice(QWidget* pWidget,QString ip)
    : m_hDevice(NULL)
    , m_strIP(ip)
    , m_pBitmap(nullptr)
    , m_pWidget(pWidget)
{
}

void DahengCameraDevice::InitLib(){
    GXInitLib();
}

void DahengCameraDevice::UninitLib(){
    GXCloseLib();
}

Device* DahengCameraDevice::clone(Device* pDevice){
    m_strID = pDevice->getStrID();

    m_strIP = ((DahengCameraDevice*)pDevice)->GetIP();
    m_strMAC = ((DahengCameraDevice*)pDevice)->GetMAC();
    m_strCameraName = ((DahengCameraDevice*)pDevice)->GetCameraName();
    m_nPort = ((DahengCameraDevice*)pDevice)->GetPort();
    return this;
}

void DahengCameraDevice::writeXML(QXmlStreamWriter &writer){
    // 写入当前操作的信息
    writer.writeStartElement("DahengCameraDevice");
    writer.writeAttribute(QStringLiteral("id"), m_strID);

    writer.writeTextElement("ip", m_strIP);
    writer.writeTextElement("port", QString::number(m_nPort));
    writer.writeEndElement(); // 结束当前操作的元素
}

void DahengCameraDevice::readFromXML(QXmlStreamReader &reader){
    QXmlStreamAttributes attributes = reader.attributes();
    if (attributes.hasAttribute("id")) {
        m_strID = attributes.value("id").toString();
    }

    QXmlStreamReader::TokenType token = reader.readNext();
    while (!(reader.tokenType() == QXmlStreamReader::EndElement
             && reader.name() == QStringLiteral("DahengCameraDevice"))) {
        if (reader.name() == QStringLiteral("ip")) {
            m_strIP = reader.readElementText();
        } else if (reader.name() == QStringLiteral("port")) {
            m_nPort = reader.readElementText().toInt();
        }

        reader.readNext();
    }
}

int DahengCameraDevice::SetViedoWidget(QWidget* pWidget){
    GX_STATUS emStatus  = GX_STATUS_SUCCESS;
    m_pWidget = pWidget;
    do{
        m_hWidgetCamera = (HWND)m_pWidget->winId();
        m_pBitmap = new CGXBitmap(m_hDevice,m_hWidgetCamera);
    }while(false);

    // 为图像显示准备资源
    emStatus = m_pBitmap->PrepareForShowImg();

    // (3) 注册回调函数
    ConfigureCamera();

    return emStatus;
}

int DahengCameraDevice::initDevice(){
    GX_STATUS emStatus  = GX_STATUS_SUCCESS;
    uint32_t nDSNum;
    // (1) 打开设备
    OpenCamera();

    // (2) 初始化网络数据包
    InitCamera();

    return emStatus;
}

void DahengCameraDevice::uninitDevice(){
    // 为图像显示准备资源
    if(m_pBitmap != nullptr){
        m_pBitmap->UnPrepareForShowImg();

        delete m_pBitmap;
    }

    CloseCamera();
}

QString DahengCameraDevice::getClassName(){
    return this->metaObject()->className();
}

int DahengCameraDevice::OpenCamera(){
    m_emStatus                  = GX_STATUS_SUCCESS;

    m_stOpenParam.accessMode    = GX_ACCESS_EXCLUSIVE;
    m_stOpenParam.openMode      = GX_OPEN_IP;
    QByteArray ba               = m_strIP.toLatin1();
    m_stOpenParam.pszContent    = ba.data();

    m_emStatus = GXOpenDevice(&m_stOpenParam,&m_hDevice);
    if(m_emStatus != GX_STATUS_SUCCESS){
        qDebug() << "打开相机失败！";
        return m_emStatus;
    }
    qDebug() << "打开相机成功！";
    return m_emStatus;
}

int DahengCameraDevice::ReadCameraParameter(){
    m_emStatus = GX_STATUS_SUCCESS;

    //获取厂商名称
    GX_STRING_VALUE stVendorNameValue;
    const char* pszVendorName = NULL;
    m_emStatus = GXGetStringValue(m_hDevice, "DeviceVendorName", &stVendorNameValue);
    pszVendorName = stVendorNameValue.strCurValue;
    m_strVendorName = QString::fromStdString(pszVendorName);

    //获取设备型号
    GX_STRING_VALUE stDeviceModelValue;
    const char* pszDeviceModel = NULL;
    m_emStatus = GXGetStringValue(m_hDevice, "DeviceModelName",&stDeviceModelValue);
    pszDeviceModel = stDeviceModelValue.strCurValue;
    m_strDeviceModel = QString::fromStdString(pszDeviceModel);

    // 设备序列号
    GX_STRING_VALUE stSerialNumberValue;
    const char* pszSerialNumberValue = NULL;
    m_emStatus = GXGetStringValue(m_hDevice, "DeviceSerialNumber",&stSerialNumberValue);
    pszSerialNumberValue = stSerialNumberValue.strCurValue;
    m_strSerialNumber = QString::fromStdString(pszSerialNumberValue);

    //获取自定义名称
    GX_STRING_VALUE stUserIDValue;
    const char* pszUserID = NULL;
    m_emStatus = GXGetStringValue(m_hDevice, "DeviceUserID",&stUserIDValue);
    pszUserID = stUserIDValue.strCurValue;
    m_strUserID = QString::fromStdString(pszUserID);

    return m_emStatus;
}

int DahengCameraDevice::InitCamera(){
    uint32_t nDSNum;
    m_emStatus = GX_STATUS_SUCCESS;

    // 获取流通道数
    m_emStatus = GXGetDataStreamNumFromDev(m_hDevice,&nDSNum);
    if(nDSNum > 0){
        m_emStatus = GXGetDataStreamHandleFromDev(m_hDevice,1,&m_hStream);
    }

    // 建议用户在打开网络相机之后，根据当前网络环境设置相机的流通道包长值
    // 以提高网络相机的采集性能，设置方法如下
    {
        bool bImplementPackSize = false;
        uint32_t unPacketSize = 0;

        // 判断设备是否支持流通道数据包功能
        GX_NODE_ACCESS_MODE emAccessMode = GX_NODE_ACCESS_MODE_NI;
        m_emStatus = GXGetNodeAccessMode(m_hDevice,"GevSCPSPacketSize",&emAccessMode);

        if((emAccessMode != GX_NODE_ACCESS_MODE_NI)
            && (emAccessMode != GX_NODE_ACCESS_MODE_UNDEF)
            && (emAccessMode != GX_NODE_ACCESS_MODE_NA)){
            bImplementPackSize = true;
        }

        if(bImplementPackSize){
            m_emStatus = GXGetOptimalPacketSize(m_hDevice,&unPacketSize);

            m_emStatus = GXSetIntValue(m_hDevice,"GevSCPSPacketSize",unPacketSize);
        }
    }
    // 保存单张图像准备
    GX_INT_VALUE stPayLoadSize;
    m_emStatus = GXGetIntValue(m_hDevice, "PayloadSize", &stPayLoadSize);
    m_stFrameData.pImgBuf = malloc((size_t)stPayLoadSize.nCurValue);


    ReadCameraParameter();

    return m_emStatus;
}

int DahengCameraDevice::UninitCamera(){
    m_emStatus = GX_STATUS_SUCCESS;
    //释放图像缓冲区 buffer
    free(m_stFrameData.pImgBuf);
    return m_emStatus;
}

int DahengCameraDevice::ConfigureCamera(){
    //注册图像处理回调函数
    m_emStatus = GXRegisterCaptureCallback(m_hDevice, m_pWidget, OnFrameCallbackFun);
    if(m_emStatus != GX_STATUS_SUCCESS){
        qDebug() << "注册回调函数失败！";
        return m_emStatus;
    }
    qDebug() << "注册回调函数成功！";
    return m_emStatus;
}

int DahengCameraDevice::AcquisitionStart(){
    m_emStatus  = GX_STATUS_SUCCESS;
    m_emStatus = GXSetCommandValue(m_hDevice,"AcquisitionStart");
    if(m_emStatus != GX_STATUS_SUCCESS){
        qDebug() << "开始采集失败！";
        return m_emStatus;
    }
    qDebug() << "开始采集成功！";
    return m_emStatus;
}

int DahengCameraDevice::AcquisitionStop(){
    m_emStatus  = GX_STATUS_SUCCESS;
    m_emStatus = GXSetCommandValue(m_hDevice, "AcquisitionStop");
    if(m_emStatus != GX_STATUS_SUCCESS){
        qDebug() << "停止采集失败！";
        return m_emStatus;
    }
    qDebug() << "停止采集成功！";
    return m_emStatus;
}

int DahengCameraDevice::UnconfigureCamera(){
    m_emStatus  = GX_STATUS_SUCCESS;
    //注销采集回调
    m_emStatus = GXUnregisterCaptureCallback(m_hDevice);
    if(m_emStatus != GX_STATUS_SUCCESS){
        qDebug() << "逆初始化失败！";
        return m_emStatus;
    }
    qDebug() << "逆初始化成功！";
    return m_emStatus;
}

void DahengCameraDevice::writeBmpFile(char *data, int w, int h,int imageNum)
{
    BITMAPFILEHEADER bitmapfileheader;  //bmp 头文件  14个字节
    bitmapfileheader.bfType = 0x4D42;//表示文件类型，BMP格式的文件这两个字节是0x4D42，10进制就是19778，字符显示就是‘BM’；
    bitmapfileheader.bfReserved1 = 0;//保留位必须设置为0
    bitmapfileheader.bfReserved2 = 0;//保留位必须设置为0
    bitmapfileheader.bfOffBits = 14 + 40;   //4字节的偏移

    BITMAPINFO  bitmapinfo;
    ZeroMemory(&bitmapinfo, sizeof(bitmapinfo));

    bitmapinfo.bmiHeader.biSize = sizeof(bitmapinfo.bmiHeader);  //40byte
    bitmapinfo.bmiHeader.biWidth = w;
    bitmapinfo.bmiHeader.biHeight = h;
    bitmapinfo.bmiHeader.biPlanes = 1;//颜色平面数 一般设置为1
    bitmapinfo.bmiHeader.biBitCount = 24;//每个像素占的bit数  1，2,4,8,16,24,32
    bitmapinfo.bmiHeader.biCompression = BI_RGB;  //压缩类型 常用是0表示不压缩
    bitmapinfo.bmiHeader.biSizeImage = (w * bitmapinfo.bmiHeader.biBitCount + 31) / 32 * 4 * h;//位图的大小
    bitmapinfo.bmiHeader.biClrUsed = 0;//2的biBitCount次方
    bitmapinfo.bmiHeader.biClrImportant = 0;
    bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
    bitmapinfo.bmiHeader.biYPelsPerMeter = 0;

    QString pathname = "d:\\test\\seat\\";
    QString filename = "seatface";

    QFile hfile(pathname + filename + QString::number(imageNum) + ".bmp");
    if (hfile.open(QFile::WriteOnly))
    {
        char* bh = reinterpret_cast<char*>(&bitmapfileheader);
        hfile.write(bh, sizeof(bitmapfileheader));

        char *info = reinterpret_cast<char*>(&bitmapinfo);
        hfile.write(info, sizeof(bitmapinfo.bmiHeader));

        hfile.write(data, bitmapinfo.bmiHeader.biSizeImage);
    }
    hfile.close();
}

int DahengCameraDevice::CloseCamera(){
    m_emStatus  = GX_STATUS_SUCCESS;
    m_emStatus = GXCloseDevice(m_hDevice);
    if(m_emStatus != GX_STATUS_SUCCESS){
        qDebug() << "关闭失败！";
        return m_emStatus;
    }
    qDebug() << "关闭成功！";
    return m_emStatus;
}

#ifdef MULTITHREAD
void DahengCameraDevice::writeData(const QVariant &data){
    QMap<QString,QVariant> map = data.toMap();
    int imageNum = ((QVariant)map["content"]).toInt();
    char* pOutBuffer = MainWindow::instance()->GetImageSrcBuffer(imageNum);

    map.insert("nImageNum",     imageNum);
    map.insert("hDevice",       QVariant::fromValue((void *) m_hDevice));
    map.insert("pFrameData",    QVariant::fromValue((void *) &m_stFrameData));
    map.insert("pOutBuffer",    QVariant::fromValue((void *) pOutBuffer));

    DahengCameraTask* pTask = new DahengCameraTask();
    pTask->SetParameters(map);
    QThreadPool::globalInstance()->start(pTask);
}
#else
void DahengCameraDevice::writeData(const QVariant &data){
    QMap<QString,QVariant> map = data.toMap();
    int imageNum = ((QVariant)map["content"]).toInt();
    qDebug() << "content = " << imageNum;

    int nWidth = m_stFrameData.nWidth;
    int nHeight = m_stFrameData.nHeight;
    char* pSrcBuffer = MainWindow::instance()->GetImageSrcBuffer(imageNum);
    //每次发送触发命令之前清空采集输出队列
    //防止库内部缓存帧，造成本次GXGetImage得到的图像是上次发送触发得到的图
    m_emStatus = GXFlushQueue(m_hDevice);
    qint64 CurrentMEpoch1 = QDateTime::currentMSecsSinceEpoch();
    qint64 CurrentMEpoch2 = QDateTime::currentMSecsSinceEpoch();
    //发送开始采集命令
    m_emStatus = GXSetCommandValue(m_hDevice, "AcquisitionStart");
    //获取图像
    while(GXGetImage(m_hDevice, &m_stFrameData, 100) != GX_STATUS_SUCCESS)
    {
        Sleep(10);
    }
    CurrentMEpoch2 = QDateTime::currentMSecsSinceEpoch();
    if (m_stFrameData.nStatus == GX_FRAME_STATUS_SUCCESS)
    {
        //图像获取成功
        //对图像进行处理...
        DxRaw8toRGB24(m_stFrameData.pImgBuf,
                      pSrcBuffer,
                      nWidth,
                      nHeight,
                      DX_BAYER_CONVERT_TYPE::RAW2RGB_ADAPTIVE,
                      DX_PIXEL_COLOR_FILTER::BAYERRG,
                      true);

        emit finishSnapImage(imageNum);

        //writeBmpFile(pSrcBuffer,nWidth,nHeight,imageNum);

        qDebug() << "图像获取成功！";
    }
    CurrentMEpoch2 = QDateTime::currentMSecsSinceEpoch();
    qDebug() << "采集一张图片，耗时：" << QString::number(CurrentMEpoch2 - CurrentMEpoch1) << "毫秒";
    //writeBmpFile(pSrcBuffer,nWidth,nHeight,imageNum);
    //发送停止采集命令
    m_emStatus = GXSetCommandValue (m_hDevice, "AcquisitionStop");

}
#endif

int DahengCameraDevice::SnapImage(){
    m_emStatus  = GX_STATUS_SUCCESS;
    int imageNum = 0;
    GX_FRAME_DATA       m_stFrameData;

    qDebug() << "content = " << imageNum;

    //每次发送触发命令之前清空采集输出队列
    //防止库内部缓存帧，造成本次GXGetImage得到的图像是上次发送触发得到的图
    m_emStatus = GXFlushQueue(m_hDevice);

    //发送软触发命令
    //m_emStatus = GXSetCommandValue(m_hDevice,"TriggerSoftware");
    GX_INT_VALUE stPayLoadSize;
    //获取图像 buffer 大小，下面动态申请内存
    m_emStatus = GXGetIntValue(m_hDevice, "PayloadSize", &stPayLoadSize);
    m_stFrameData.pImgBuf = malloc((size_t)stPayLoadSize.nCurValue);
    //发送开始采集命令
    m_emStatus = GXSetCommandValue(m_hDevice, "AcquisitionStart");
    //获取图像
    while(GXGetImage(m_hDevice, &m_stFrameData, 100) != GX_STATUS_SUCCESS)
    {
        Sleep(10);
    }
    if (m_stFrameData.nStatus == GX_FRAME_STATUS_SUCCESS)
    {
        //图像获取成功
        //对图像进行处理...

        qDebug() << "图像获取成功！";
    }

    //发送停止采集命令
    m_emStatus = GXSetCommandValue (m_hDevice, "AcquisitionStop");
    //释放图像缓冲区 buffer
    free(m_stFrameData.pImgBuf);
    return m_emStatus;
}
